<?php
/**
 * pincode.class.php
 * 
 * 生成、显示、验证码
 * @author tommy <streen003@gmail.com>
 * @copyright Copyright (c) 2010 Tommycode Studio
 * @link http://www.doitphp.com
 * @license New BSD License.{@link http://www.opensource.org/licenses/bsd-license.php}
 * @version $Id: pincode.class.php 1.0 2011-8-11 PM11:33:41Z tommy $
 * @package lib
 * @since 1.0
 */
 
if (!defined('IN_DOIT')) {
	exit();
}

class pincode extends Base {
	
	/**
	 * 验证码图片的背景图片.
	 * 
	 * @var string
	 */
	public $image_url;
	
	/**
	 * 字体名称
	 * 
	 * @var sting
	 */
	public $font_name;
	
	/**
	 * 字体大小
	 * 
	 * @var integer
	 */
	public $font_size;
	
	/**
	 * 图片实例化名称
	 * 
	 * @var object
	 */
	protected $image;	
	
	/**
	 * 图象宽度
	 * 
	 * @var integer
	 */
	protected $width;
	
	/**
	 * 图象高度
	 * 
	 * @var integer
	 */
	protected $height;
	
	/**
	 * 图片格式, 如:jpeg, gif, png
	 * 
	 * @var string
	 */
	protected $type;
	
	/**
	 * 字体颜色
	 * 
	 * @var string
	 */
	protected $font_color;
	
	/**
	 * 背景的颜色
	 * 
	 * @var string
	 */
	protected $bg_color;
	
	/**
	 * 验证码内容
	 * 
	 * @var string
	 */
	protected $text_content;
	
	/**
	 * 生成验证码SESSION的名称,用于类外数据验证
	 * 
	 * @var string
	 */
	public $session_name;
	
	
	/**
	 * 构造函数
	 * 
	 * @access public 
	 * @return boolean
	 */
	public function __construct() {		
				
		$this->font_size 	= 14;		
		$this->font_name 	= DOIT_ROOT . 'views/source/aispec.ttf';
		$this->session_name = 'doitphp_pincode_session_id';
		$this->width		= 90;
		$this->height		= 30;
				
		return true;
	}
		
	/**
	 * 设置字体名称.
	 * 
	 * @param sting $name	字体名称(字体的路径)	
	 * @param integer $size	字体大小
	 */
	public function set_font_name($name, $size = null) {
		
		if (!empty($name)) {
			$this->font_name = $name;
		}		
		if (!is_null($size)) {
			$this->font_size = intval($size);
		}
		
		return $this;
	}
	
	/**
	 * 设置字体大小.
	 * 
	 * @param integer $size	字体大小
	 * @return $this
	 */
	public function set_font_size($size) {
		
		if (!empty($size)) {
			$this->font_size = intval($size);
		}
				
		return $this;
	}

	/**
	 * 设置背景图片或水印图片的URL.
	 * 
	 * @param string $url	图片的路径(图片的实际地址)
	 * @return $this
	 */
	public function set_bg_image($url) {
		
		if (!empty($url)) {
			$this->image_url = $url;
		}
				
		return $this;
	}
	
	/**
	 * 设置生成图片的大小.
	 * 
	 * @param integer $width	图片的宽度
	 * @param integer $height	图片的高度
	 * @return $this
	 */
	public function set_image_size($width, $height) {
		
		if (!empty($width)) {
			$this->width = (int)$width;
		}
		if (!empty($height)) {
			$this->height = (int)$height;
		}
				
		return $this;
	}
	
	/**
	 * 设置验证码的session_name.
	 * 
	 * @param string $name
	 */
	public function set_session_name($name) {
		
		if (!empty($name)) {
			$this->session_name = $name;
		}
		
		return $this;
	}
	
	/**
	 * 设置验证码内容.
	 * 
	 * @param string $content
	 * @return $this
	 */
	public function set_text_content($content) {
		
		if (!empty($content)) {
			$this->text_content = $content;
		}
		
		return $this;
	}
	
	/**
	 * 获取颜色参数.
	 * 
	 * @param string $param	颜色参数. 如：#FF0000
	 * @return $this
	 */
	public function set_text_color($param) {
		
		//将十六进制颜色值转化为十进制
		$x = hexdec(substr($param, 1, 2));
		$y = hexdec(substr($param, 3, 2));
		$z = hexdec(substr($param, 5, 2));
			  		
		$this->font_color = array($x, $y, $z);
				
		return $this;
	}
	
	/**
	 * 获取背景的颜色参数
	 * 
	 * @param string $param	颜色参数. 如：#FF0000
	 * @return $this
	 */
	public function set_bg_color($param) {
		
		//将十六进制颜色值转化为十进制
		$x = hexdec(substr($param, 1, 2));
		$y = hexdec(substr($param, 3, 2));
		$z = hexdec(substr($param, 5, 2));
		
		$this->bg_color = array($x, $y, $z);
		
		return $this;
	}
	
	/**
	 * 生成验证码内容.
	 * 
	 * @return stirng
	 */
	protected function get_pincode_content() {
		
		if (!$this->text_content) {
			$char = 'BCEFGHJKMPQRTVWXY2346789';		
			$num1 = $char[mt_rand(0, 23)];		
			$num2 = $char[mt_rand(0, 23)];		
			$num3 = $char[mt_rand(0, 23)];		
			$num4 = $char[mt_rand(0, 23)];		
			$this->text_content = $num1 . $num2 . $num3 . $num4;	
		}
							
		return $this->text_content;
	}

	/**
	 * 验证码的判断
	 * 
	 * @access public
	 * @param string $code	待验证的验证码内容
	 * @return boolean
	 */
	public function check($code) {
		
		if (!$code) {
			return false;
		}
		$code = strtolower($code);
		
		//start session
		session_start();
				
		return (isset($_SESSION[$this->session_name]) && (strtolower($_SESSION[$this->session_name]) == $code)) ? true : false;
	} 
		
	/**
	 * 显示验证码.
	 * 
	 * @access public
	 * @param string $image_url	验证码的背影图片路径
	 * @return void
	 */
	public function show($image_url = null) {
		
		//当前面没有session_start()调用时.
		session_start();
		
		if (!is_null($image_url)) {
			$this->image_url = trim($image_url);
		}				
		
		$this->image = (!function_exists('imagecreatetruecolor')) ? imagecreate($this->width, $this->height) : imagecreatetruecolor($this->width, $this->height);
		
		//当有背景图片存在时
		if ($this->image_url) {			
			
			//初始化图片信息.
			list($image_width, $image_height, $type) = getimagesize($this->image_url);
			
			//分析图片的格式
			switch ($type) {					
				case 1:
					$image 			= imagecreatefromgif ($this->image_url);
					$this->type 	= 'gif';
					break;
									
				case 2:
					$image 			= imagecreatefromjpeg($this->image_url);
					$this->type 	= 'jpg';
					break;
										
				case 3:
					$image 			= imagecreatefrompng($this->image_url);
					$this->type 	= 'png';
					break;
										
				case 4:
					$image 			= imagecreatefromwbmp($this->image_url);
					$this->type 	= 'bmp';
					break;				
			}
											
			//背景
			$src_x = ($image_width > $this->width) ? mt_rand(0, $image_width - $this->width) : 0;
			$src_y = ($image_height > $this->height) ? mt_rand(0, $image_height - $this->height) : 0;							
			imagecopymerge($this->image, $image, 0, 0, $src_x, $src_y, $this->width, $this->height, 100);
			imagedestroy($image);
			
			//边框
			$border_color	= imagecolorallocate($this->image, 255, 255, 255);
			imagerectangle($this->image, 1, 1, $this->width - 2, $this->height - 2, $border_color);
			
		} else {
			
			//定义图片类型			
			$this->type 	= 'png';
			
			//背景
			$bg_color_array = (!$this->bg_color) ? array(255, 255, 255) : $this->bg_color;			
			$back_color = imagecolorallocate($this->image, $bg_color_array[0], $bg_color_array[1], $bg_color_array[2]);
			imagefilledrectangle($this->image, 0, 0, $this->width -1, $this->height - 1, $back_color);
			
			//边框
			$border_color	= imagecolorallocate($this->image, 238, 238, 238);
			imagerectangle($this->image, 0, 0, $this->width - 1, $this->height - 1, $border_color);							
		}
		
		//获取验证码内容.
		$this->get_pincode_content();
		
		//验证码中含有汉字
		if (!preg_match('~[\x{4e00}-\x{9fa5}]+~u', $this->text_content)) {
			//计算验证码的位数
			$code_strlen = strlen($this->text_content);
			//每位验证码所占用的图片宽度		
			$per_width = ceil(($this->width - 10)/ $code_strlen);

			for($i = 0; $i < $code_strlen; $i ++) {
			
				//获取单个字符
				$text_content = $this->text_content[$i];
			
				$bbox = imagettfbbox($this->font_size, 0, $this->font_name, $text_content);				
				$font_w = $bbox[2]-$bbox[0];		
				$font_h = abs($bbox[7]-$bbox[1]);
			
				$font_x = ceil(($per_width - $font_w) / 2) + $per_width * $i + 5;
				$min_y	= $font_h + 5;	
				$max_y	= $this->height -5;				
				$font_y = rand($min_y, $max_y);			
			
				$font_color = (!$this->font_color) ? imagecolorallocate($this->image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)) : imagecolorallocate($this->image, $this->font_color[0], $this->font_color[1], $this->font_color[2]);
				imagettftext($this->image, $this->font_size, 0, $font_x, $font_y, $font_color, $this->font_name, $text_content);
			}
		} else {
			//分析验证码的位置
			$bbox = imagettfbbox($this->font_size, 0, $this->font_name, $this->text_content);				
			$font_w = $bbox[2]-$bbox[0];		
			$font_h = abs($bbox[7]-$bbox[1]);
			$font_x = ceil(($this->width - $font_w) / 2) + 5;
			$min_y	= $font_h + 5;	
			$max_y	= $this->height -5;				
			$font_y = rand($min_y, $max_y);
			
			$font_color = (!$this->font_color) ? imagecolorallocate($this->image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)) : imagecolorallocate($this->image, $this->font_color[0], $this->font_color[1], $this->font_color[2]);
			imagettftext($this->image, $this->font_size, 0, $font_x, $font_y, $font_color, $this->font_name, $this->text_content);
		}		

		//干扰线
		for ($i = 0; $i < 5; $i ++) {
			$line_color = imagecolorallocate($this->image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
			imageline($this->image, mt_rand(2, $this->width - 3), mt_rand(2, $this->height  - 3), mt_rand(2, $this->width  - 3), mt_rand(2, $this->height  - 3), $line_color);
		}
		
		//将显示的验证码赋值给session.
		$_SESSION[$this->session_name] = $this->text_content;
		
		//当有headers内容输出时.
		if (headers_sent()) {
			Controller::halt('headers already sent'); 
		}
		
		//显示图片,根据背景图片的格式显示相应格式的图片.
		switch ($this->type) {
			
			case 'gif':
				header('Content-type:image/gif');
				imagegif ($this->image);
				break;
				
			case 'jpg':
				header('Content-type:image/jpeg');
				imagejpeg($this->image);
				break;
				
			case 'png':
				header('Content-type:image/png');
				imagepng($this->image);
				break;
				
			case 'bmp':
				header('Content-type:image/wbmp');
				imagewbmp($this->image);
				break;
		}
						
		imagedestroy($this->image);
	}
}